package com.devo.icecream.modbus

import android.os.Handler
import android.util.ArrayMap
import com.devo.icecream.AppLogger
import com.devo.icecream.utils.plcIdToBucketId
import com.serotonin.modbus4j.BatchRead
import com.serotonin.modbus4j.ModbusMaster
import com.serotonin.modbus4j.code.DataType
import com.serotonin.modbus4j.locator.BaseLocator

class Stock(private val master: ModbusMaster, private val workHandler: Handler) {
    //库存1状态对应列表 按照规则将桶位的ID转换成PLC_ID  该id对应的量是否充足
    private val warns = ArrayMap<Int, Boolean>()

    //库存2状态对应列表
    private val stocks = ArrayMap<Int, Float>()

    //杯子库存状态
    private var isCupWarning = false;

    //杯盖库存状态
    private var isCupCoverWarning = false;

    private val warnStart = 5002 //库存表 0正常 1缺料 5002~5046
    private val warnEnd = 5046//库存表 0正常 1缺料 5002~5046

    private val stockStart = 46090//检查库存 库存开始
    private val stockEnd = 46134//检查库存 库存结束

    private val cupWarn = 2023//杯子库存
    private val cupCoverWarn = 2024//盖勺库存

    private val skip = 2

    //检查库存1 5002~ 5046
    private val warnRequests by lazy {
        (warnStart..warnEnd step skip).map {
            BaseLocator.inputStatus(1, it)
        }
    }

    //检查库存2 46090~ 46134
    private val stockRequests by lazy {
        (stockStart..stockEnd step skip).map {
            BaseLocator.holdingRegister(1, it, DataType.FOUR_BYTE_FLOAT_SWAPPED)
        }
    }

    private fun loopQuery() {
        workHandler.postDelayed({
            //检查库存1
            queryWarning()
            //检查库存2
            queryStock()
            //查询被子和杯盖的库存
            queryCupWaring()

            loopQuery()
        }, 1000)
    }

    //查询被子和杯盖的库存
    private fun queryCupWaring() {
        val time = System.currentTimeMillis().toString()
        var offset = 0

        val batchRead = BatchRead<String>().apply {
            addLocator("${time}-${++offset}", BaseLocator.inputStatus(1, cupWarn))
            addLocator("${time}-${++offset}", BaseLocator.inputStatus(1, cupCoverWarn))
        }
        offset = 0

        try {
            val results = master.send(batchRead)

            isCupWarning = results.getValue("${time}-${++offset}") as Boolean
            isCupCoverWarning = results.getValue("${time}-${++offset}") as Boolean

        } catch (e: Exception) {
            AppLogger.e("查询杯盖和杯子库存报错", e)
        }


    }

    //检查库存1
    private fun queryWarning() {
        val time = System.currentTimeMillis().toString() + "-"
        var offset = 0

        val batchRead = BatchRead<String>().apply {
            //检查库存1 5002~ 5046
            warnRequests.forEach {
                addLocator(time + ++offset, it)
            }
        }

        try {
            val results = master.send(batchRead)
            synchronized(this) {
                warns.clear()
                var serial = 0
                offset = 0
                var step = warnStart
                while (step in (warnStart..warnEnd step skip)) {
                    //按照规则将桶位的ID转换成PLC_ID  查看该桶位ID的量是否充足
                    warns[++serial] = results.getValue(time + ++offset) as Boolean
                    step += skip
                }
            }
        } catch (e: Exception) {
            AppLogger.e(e, "queryStock")
        }
    }

    //检查库存2
    private fun queryStock() {
        val batchRead = BatchRead<String>()
        val time = System.currentTimeMillis().toString() + "-"
        var offset = 0
        //检查库存2 46090~ 46134
        stockRequests.forEach {
            batchRead.addLocator(time + ++offset, it)
        }

        try {
            //给plc发送 去查询这些状态下的库存量
            val results = master.send(batchRead)
            synchronized(this) {
                stocks.clear()
                var serial = 0
                offset = 0
                var step = stockStart
                while (step in (stockStart..stockEnd step skip)) {
                    stocks[++serial] = results.getFloatValue(time + ++offset)
                    step += skip
                }
            }
        } catch (e: Exception) {
            AppLogger.e(e, "queryStock")
        }

    }


    //库存1 是否需要补料 【按照规则将桶位的ID转换成PLC_ID 将plcID传入来判断这个桶里面的量是不是够了】
    @Synchronized
    fun needSupply(serial: Int): Boolean {
        return if (warns.containsKey(serial)) warns[serial]!! else false
    }

    //库存2 桶位 获取库存状态
    fun getStockStatus(): Map<String, Map<String, Float>> {
        if (stocks.size != warns.size) {
            return mapOf()
        }
        return stocks.entries.zip(warns.entries) { s, w ->
            val bucketId = plcIdToBucketId(s.key)
            bucketId to mapOf(
                "inventory" to s.value,
                "status" to if (w.value) 2f else 1f
            )
        }.toMutableList().apply {
            addAll(
                listOf(
                    "CUP" to mapOf(
                        "inventory" to 0f,
                        "status" to if (isCupWarning) 2f else 1f
                    ),
                    "CUP_COVER" to mapOf(
                        "inventory" to 0f,
                        "status" to if (isCupCoverWarning) 2f else 1f
                    )
                )
            )
        }.toMap()
    }

    companion object {
        private const val TAG = "PLCStock"
    }

    init {
        loopQuery()
    }
}